from vpython import *
import tkinter as tk
from tkinter import ttk, colorchooser
import numpy as np
from time import sleep

class TileWall3DDesigner:
    def __init__(self):
        # 创建主窗口
        self.root = tk.Tk()
        self.root.title("3D瓷砖墙体设计器")
        
        # 默认参数
        self.wall_width = 300  # cm
        self.wall_height = 250  # cm
        self.wall_depth = 2    # cm
        self.tile_width = 60   # cm
        self.tile_height = 60  # cm
        self.tile_depth = 1    # cm
        self.tile_color = vector(0.8, 0.8, 0.8)  # 灰色
        
        # 添加标注开关
        self.show_dimensions = True
        
        self.dragging = False
        self.last_mouse_pos = None
        
        self.create_ui()
        self.create_3d_scene()
        
    def create_ui(self):
        # 创建控制面板
        control_frame = ttk.LabelFrame(self.root, text="控制面板", padding="5")
        control_frame.grid(row=0, column=0, padx=5, pady=5, sticky='n')
        
        # 墙体尺寸输入
        ttk.Label(control_frame, text="墙体尺寸 (cm)").grid(row=0, column=0, columnspan=2)
        
        ttk.Label(control_frame, text="宽度:").grid(row=1, column=0)
        self.wall_width_var = tk.StringVar(value="300")
        ttk.Entry(control_frame, textvariable=self.wall_width_var).grid(row=1, column=1)
        
        ttk.Label(control_frame, text="高度:").grid(row=2, column=0)
        self.wall_height_var = tk.StringVar(value="250")
        ttk.Entry(control_frame, textvariable=self.wall_height_var).grid(row=2, column=1)
        
        ttk.Label(control_frame, text="深度:").grid(row=3, column=0)
        self.wall_depth_var = tk.StringVar(value="2")
        ttk.Entry(control_frame, textvariable=self.wall_depth_var).grid(row=3, column=1)
        
        # 瓷砖尺寸输入
        ttk.Label(control_frame, text="瓷砖尺寸 (cm)").grid(row=4, column=0, columnspan=2, pady=(10,0))
        
        ttk.Label(control_frame, text="宽度:").grid(row=5, column=0)
        self.tile_width_var = tk.StringVar(value="60")
        ttk.Entry(control_frame, textvariable=self.tile_width_var).grid(row=5, column=1)
        
        ttk.Label(control_frame, text="高度:").grid(row=6, column=0)
        self.tile_height_var = tk.StringVar(value="60")
        ttk.Entry(control_frame, textvariable=self.tile_height_var).grid(row=6, column=1)
        
        ttk.Label(control_frame, text="厚度:").grid(row=7, column=0)
        self.tile_depth_var = tk.StringVar(value="1")
        ttk.Entry(control_frame, textvariable=self.tile_depth_var).grid(row=7, column=1)
        
        # 颜色选择按钮
        ttk.Button(control_frame, text="选择瓷砖颜色", 
                  command=self.choose_color).grid(row=8, column=0, columnspan=2, pady=5)
        
        # 更新按钮
        ttk.Button(control_frame, text="更新3D视图", 
                  command=self.update_3d_view).grid(row=9, column=0, columnspan=2)
        
        # 计算按钮
        ttk.Button(control_frame, text="计算瓷砖数量", 
                  command=self.calculate_tiles).grid(row=10, column=0, columnspan=2, pady=5)
        
        # 添加标注开关按钮
        ttk.Checkbutton(control_frame, text="显示尺寸标注", 
                       command=self.toggle_dimensions).grid(
                           row=11, column=0, columnspan=2)
        
        # 结果显示区域移到更下面
        self.result_text = tk.Text(control_frame, height=8, width=30)
        self.result_text.grid(row=12, column=0, columnspan=2, pady=5)
        
    def create_3d_scene(self):
        # 创建3D场景
        scene.width = 800
        scene.height = 600
        scene.background = color.white
        scene.caption = "3D瓷砖墙体预览\n拖动鼠标旋转视角，滚轮缩放"
        
        # 添加鼠标事件绑定
        scene.bind('mousedown', self.on_mouse_down)
        scene.bind('mouseup', self.on_mouse_up)
        scene.bind('mousemove', self.on_mouse_move)
        
        self.update_3d_view()
    
    def on_mouse_down(self, event):
        self.dragging = True
        self.last_mouse_pos = event.pos
    
    def on_mouse_up(self, event):
        self.dragging = False
        self.last_mouse_pos = None
    
    def on_mouse_move(self, event):
        if self.dragging and self.last_mouse_pos:
            # 计算鼠标移动距离
            dx = event.pos.x - self.last_mouse_pos.x
            dy = event.pos.y - self.last_mouse_pos.y
            
            # 旋转场景
            scene.camera.pos = scene.camera.pos.rotate(
                angle=-dx*0.01,  # 水平旋转
                axis=vector(0,1,0)
            )
            scene.camera.pos = scene.camera.pos.rotate(
                angle=-dy*0.01,  # 垂直旋转
                axis=vector(1,0,0).cross(scene.camera.pos)
            )
            
            # 始终看向原点
            scene.camera.axis = -scene.camera.pos
            
            self.last_mouse_pos = event.pos
        
    def choose_color(self):
        color = colorchooser.askcolor(
            color='#CCCCCC',
            title="选择瓷砖颜色"
        )
        if color[0]:  # color[0] 是 RGB 元组
            r, g, b = [x/255 for x in color[0]]
            self.tile_color = vector(r, g, b)
            self.update_3d_view()
            
    def toggle_dimensions(self):
        self.show_dimensions = not self.show_dimensions
        self.update_3d_view()
            
    def update_3d_view(self):
        try:
            # 清除现有的对象
            for obj in scene.objects:
                obj.visible = False
            
            # 获取尺寸参数
            wall_width = float(self.wall_width_var.get()) / 100  # 转换为米
            wall_height = float(self.wall_height_var.get()) / 100
            wall_depth = float(self.wall_depth_var.get()) / 100
            tile_width = float(self.tile_width_var.get()) / 100
            tile_height = float(self.tile_height_var.get()) / 100
            tile_depth = float(self.tile_depth_var.get()) / 100
            
            # 创建墙体基础
            box(pos=vector(0, 0, -wall_depth/2),
                size=vector(wall_width, wall_height, wall_depth),
                color=color.white,
                opacity=0.3)
            
            # 计算瓷砖数量
            tiles_horizontal = int(np.ceil(wall_width / tile_width))
            tiles_vertical = int(np.ceil(wall_height / tile_height))
            
            # 创建瓷砖
            for i in range(tiles_horizontal):
                for j in range(tiles_vertical):
                    x = (i * tile_width) - (wall_width/2) + (tile_width/2)
                    y = (j * tile_height) - (wall_height/2) + (tile_height/2)
                    
                    # 创建瓷砖
                    tile = box(pos=vector(x, y, 0),
                             size=vector(tile_width*0.98, tile_height*0.98, tile_depth),
                             color=self.tile_color)
                    
                    # 如果启用了标注，添加尺寸文本
                    if self.show_dimensions:
                        # 转换回厘米并保留一位小数
                        w = float(self.tile_width_var.get())
                        h = float(self.tile_height_var.get())
                        d = float(self.tile_depth_var.get())
                        
                        # 创建尺寸标注文本 - 移到瓷砖下方
                        text(pos=vector(x, y - tile_height*0.3, tile_depth/2),
                             text=f'{w:.1f}×{h:.1f}×{d:.1f}cm',
                             height=0.015,  # 减小字体大小
                             color=color.black,
                             billboard=True,
                             align='center')
                        
                        # 添加序号 - 移到瓷砖上方
                        text(pos=vector(x, y + tile_height*0.3, tile_depth/2),
                             text=f'#{i*tiles_vertical + j + 1}',
                             height=0.02,  # 增大序号字体
                             color=color.blue,
                             billboard=True,
                             align='center')
            
            # 坐标轴标注优化
            if self.show_dimensions:
                axis_length = max(wall_width, wall_height, wall_depth)
                axis_offset = 0.2  # 坐标轴偏移量
                arrow_thickness = 0.01  # 箭头粗细
                text_offset = 0.05  # 文字偏移量
                
                # 创建坐标轴原点
                sphere(pos=vector(-wall_width/2-axis_offset, -wall_height/2-axis_offset, 0),
                      radius=0.02,
                      color=color.black)
                
                # X轴（宽度）- 红色
                x_arrow = arrow(pos=vector(-wall_width/2-axis_offset, -wall_height/2-axis_offset, 0),
                              axis=vector(axis_length/2, 0, 0),
                              color=color.red,
                              shaftwidth=arrow_thickness,
                              headwidth=2*arrow_thickness,
                              headlength=3*arrow_thickness)
                
                # X轴标签动画
                x_text = text(pos=vector(-wall_width/2-axis_offset+axis_length/4, 
                                       -wall_height/2-axis_offset-text_offset, 0),
                             text=f'宽度: {self.wall_width_var.get()}cm',
                             height=0.04,
                             color=color.red,
                             align='center',
                             billboard=True,
                             opacity=0)
                
                # Y轴（高度）- 绿色
                y_arrow = arrow(pos=vector(-wall_width/2-axis_offset, -wall_height/2-axis_offset, 0),
                              axis=vector(0, axis_length/2, 0),
                              color=color.green,
                              shaftwidth=arrow_thickness,
                              headwidth=2*arrow_thickness,
                              headlength=3*arrow_thickness)
                
                # Y轴标签动画
                y_text = text(pos=vector(-wall_width/2-axis_offset-text_offset,
                                       -wall_height/2-axis_offset+axis_length/4, 0),
                             text=f'高度: {self.wall_height_var.get()}cm',
                             height=0.04,
                             color=color.green,
                             align='center',
                             billboard=True,
                             opacity=0)
                
                # Z轴（深度）- 蓝色
                z_arrow = arrow(pos=vector(-wall_width/2-axis_offset, -wall_height/2-axis_offset, 0),
                              axis=vector(0, 0, axis_length/2),
                              color=color.blue,
                              shaftwidth=arrow_thickness,
                              headwidth=2*arrow_thickness,
                              headlength=3*arrow_thickness)
                
                # Z轴标签动画
                z_text = text(pos=vector(-wall_width/2-axis_offset-text_offset,
                                       -wall_height/2-axis_offset, axis_length/4),
                             text=f'深度: {self.wall_depth_var.get()}cm',
                             height=0.04,
                             color=color.blue,
                             align='center',
                             billboard=True,
                             opacity=0)
                
                # 修改动画实现方式
                def animate_text():
                    for i in range(30):
                        rate(30)  # 控制动画速度
                        x_text.opacity = i/30
                        y_text.opacity = i/30
                        z_text.opacity = i/30
                
                # 启动动画
                animate_text()  # 直接调用动画函数

        except ValueError as e:
            print(f"输入错误: {str(e)}")
            
    def calculate_tiles(self):
        try:
            wall_width = float(self.wall_width_var.get())
            wall_height = float(self.wall_height_var.get())
            tile_width = float(self.tile_width_var.get())
            tile_height = float(self.tile_height_var.get())
            
            tiles_horizontal = int(np.ceil(wall_width / tile_width))
            tiles_vertical = int(np.ceil(wall_height / tile_height))
            total_tiles = tiles_horizontal * tiles_vertical
            
            covered_area = tiles_horizontal * tiles_vertical * tile_width * tile_height / 10000
            
            result = f"""墙体尺寸: {wall_width}×{wall_height}×{self.wall_depth_var.get()} cm
瓷砖尺寸: {tile_width}×{tile_height}×{self.tile_depth_var.get()} cm
横向数量: {tiles_horizontal}片
纵向数量: {tiles_vertical}片
总数量: {total_tiles}片
覆盖面积: {covered_area:.2f}平方米"""
            
            self.result_text.delete(1.0, tk.END)
            self.result_text.insert(tk.END, result)
            
        except ValueError:
            tk.messagebox.showerror("错误", "请输入有效的数值")
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = TileWall3DDesigner()
    app.run()